package cn.wolfcode.service.impl;

import cn.wolfcode.common.exception.BusinessException;
import cn.wolfcode.common.web.Result;
import cn.wolfcode.domain.*;
import cn.wolfcode.feign.AlipayFeignApi;
import cn.wolfcode.feign.IntegralFeignApi;
import cn.wolfcode.mapper.OrderInfoMapper;
import cn.wolfcode.mapper.PayLogMapper;
import cn.wolfcode.mapper.RefundLogMapper;
import cn.wolfcode.mapper.SeckillProductMapper;
import cn.wolfcode.mq.MQConstant;
import cn.wolfcode.mq.OrderMQResult;
import cn.wolfcode.redis.SeckillRedisKey;
import cn.wolfcode.service.IOrderInfoService;
import cn.wolfcode.service.ISeckillProductService;
import cn.wolfcode.util.IdGenerateUtil;
import cn.wolfcode.web.msg.SeckillCodeMsg;
import com.alibaba.fastjson.JSON;
import io.seata.spring.annotation.GlobalTransactional;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;

/**
 * Created by wolfcode-lanxw
 */
@Service
@RefreshScope
public class OrderInfoSeviceImpl implements IOrderInfoService {
    @Autowired
    private ISeckillProductService seckillProductService;
    @Autowired
    private OrderInfoMapper orderInfoMapper;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private PayLogMapper payLogMapper;
    @Autowired
    private RefundLogMapper refundLogMapper;
    @Autowired
    private SeckillProductMapper seckillProductMapper;
    @Autowired
    private RocketMQTemplate rocketMQTemplate;
    @Autowired
    private AlipayFeignApi alipayFeignApi;
    @Autowired
    private IntegralFeignApi integralFeignApi;
    @Value("${pay.returnUrl}")
    private String returnUrl;
    @Value("${pay.notifyUrl}")
    private String notifyUrl;
    @Override
    @Transactional
    public String doSeckill(Long seckillId, int time, Long phone) {
        //6.1减少真实库存
        int count = seckillProductMapper.decrStock(seckillId);
        if (count==0){
            throw new BusinessException(SeckillCodeMsg.SECKILL_STOCK_OVER);
        }
        //6.2创建订单并且把订单保存到数据库中t_order_info
        String orderNo = createOrder(seckillId,time,phone);
        //6.3往redis存一个数据为重复下单做铺垫
        ////set seckillOrderset:time    phone:seckillId
        redisTemplate.opsForSet().
                add(SeckillRedisKey.SECKILL_ORDER_SET.getRealKey(time+""),phone + ":" + seckillId);
        return orderNo;
    }

    private String createOrder(Long seckillId, int time, Long phone) {
        SeckillProductVo vo = seckillProductService.queryByTimeAndSid(time, seckillId);
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setCreateDate(new Date());
        orderInfo.setDeliveryAddrId(1L);
        orderInfo.setIntergral(vo.getIntergral());
        orderInfo.setProductCount(1);
        orderInfo.setProductId(vo.getProductId());
        orderInfo.setProductImg(vo.getProductImg());
        orderInfo.setProductName(vo.getProductName());
        orderInfo.setProductPrice(vo.getProductPrice());
        orderInfo.setSeckillDate(new Date());
        orderInfo.setSeckillId(vo.getId());
        orderInfo.setSeckillPrice(vo.getSeckillPrice());
        orderInfo.setSeckillTime(time);
        orderInfo.setUserId(phone);
        orderInfo.setOrderNo(IdGenerateUtil.get().nextId()+"");
        orderInfoMapper.insert(orderInfo);
        return orderInfo.getOrderNo();
    }

    @Override
    @Transactional
    public void cancelOrder(OrderMQResult orderMQResult) {
        //1.回补真实库存
        seckillProductMapper.incrStock(orderMQResult.getSeckillId());
        //2.回补预库存
        seckillProductService.syncRedisStockCount(orderMQResult.getTime(),orderMQResult.getSeckillId());
        //3.修改本地标识
        rocketMQTemplate.sendOneWay(MQConstant.CANCEL_SECKILL_OVER_SIGE_TOPIC,orderMQResult.getSeckillId());
        //4.修改订单状态
        orderInfoMapper.updateCancelStatus(orderMQResult.getOrderNo(),OrderInfo.STATUS_TIMEOUT);
    }

    @Override
    public OrderInfo find(String orderNo) {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Object o = redisTemplate.opsForHash().get(SeckillRedisKey.SECKILL_ORDER_HASH.getRealKey(""), orderNo);
        OrderInfo orderInfo = JSON.parseObject(o + "", OrderInfo.class);
        return orderInfo;
    }

    @Override
    public String payOnline(String orderNo, int type) {
        OrderInfo orderInfo = find(orderNo);
        //远程调用支付完成支付代码
        PayVo payVo = new PayVo();
        payVo.setOutTradeNo(orderNo);//订单编号
        payVo.setBody(orderInfo.getProductName());//商品描述，可空
        payVo.setSubject(orderInfo.getProductName());//订单名称，必填
        payVo.setTotalAmount(orderInfo.getSeckillPrice() + "");//付款金额，必填
        payVo.setNotifyUrl(notifyUrl);//同步回调地址
        payVo.setReturnUrl(returnUrl);//异步回调地址

        Result<String> result = alipayFeignApi.payOnline(payVo);
        if (result!=null && !result.hasError()){
            return result.getData();
        }
        return null;
    }

    @Override
    public void paySuccess(Map<String, String> params) {
        System.out.println("异步回调时间:" + new Date());
        String orderNo = params.get("out_trade_no");
        OrderInfo orderInfo = find(orderNo);
        //1.插入流水记录
        PayLog payLog = new PayLog();
        payLog.setTradeNo(orderNo);//订单编号
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        payLog.setNotifyTime(simpleDateFormat.format(new Date()));//订单修改时间
        payLog.setTotalAmount(orderInfo.getSeckillPrice() + "");//交易数值
        payLog.setPayType(PayLog.PAY_TYPE_ONLINE);
        payLogMapper.insert(payLog);
        //2.修改订单状态
        orderInfoMapper.changePayStatus(orderNo,OrderInfo.STATUS_ACCOUNT_PAID,OrderInfo.PAYTYPE_ONLINE);
    }

    @Override
    public void refundOnline(OrderInfo orderInfo) {
        //1.插入流水记录
        RefundLog refundLog = new RefundLog();
        refundLog.setOutTradeNo(orderInfo.getOrderNo());//商品订单号
        refundLog.setRefundAmount(orderInfo.getSeckillPrice() + "");//退款金额
        refundLog.setRefundTime(new Date());//退款时间
        refundLog.setRefundType(OrderInfo.PAYTYPE_ONLINE);//退款类型
        refundLog.setRefundReason("garbage 不要了");
        refundLogMapper.insert(refundLog);
        //2.远程调用支付服务进行退款操作
        RefundVo refundVo = new RefundVo();
        refundVo.setOutTradeNo(orderInfo.getOrderNo());//交易订单号
        refundVo.setRefundAmount(orderInfo.getSeckillPrice() + "");
        refundVo.setRefundReason("garbage 不要了");
        //true为退款成功，反之退款失败
        Result<Boolean> result = alipayFeignApi.refundOnline(refundVo);
        if (result !=null && !result.hasError()){
            if (!result.getData()){
                throw new BusinessException(SeckillCodeMsg.OPT_ERROR);
            }
        }
        //3.修改订单状态为退款状态
        int count = orderInfoMapper.changeRefundStatus(orderInfo.getOrderNo(), OrderInfo.STATUS_REFUND);
        if (count==0) {
            throw new BusinessException(SeckillCodeMsg.OPT_ERROR);
        }
        //4.回补真实库存
        seckillProductMapper.incrStock(orderInfo.getSeckillId());
        //5.回补预库存
        seckillProductService.syncRedisStockCount(orderInfo.getSeckillTime(),orderInfo.getSeckillId());
        //6.修改本地标识
        rocketMQTemplate.sendOneWay(MQConstant.CANCEL_SECKILL_OVER_SIGE_TOPIC,orderInfo.getSeckillId());
    }

    @Override
    @GlobalTransactional
    public void payIntegral(String orderNo, int type) {
        //插入流水记录
        OrderInfo orderInfo = find(orderNo);
        PayLog payLog = new PayLog();
        payLog.setTradeNo(orderNo);//订单编号
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        payLog.setNotifyTime(simpleDateFormat.format(new Date()));//订单修改时间
        payLog.setTotalAmount(orderInfo.getIntergral() + "");//交易数值
        payLog.setPayType(PayLog.PAY_TYPE_INTERGRAL);
        payLogMapper.insert(payLog);
        //2.远程调用积分服务进行退款操作
        OperateIntergralVo operateIntergralVo = new OperateIntergralVo();
        operateIntergralVo.setPk(orderNo);//订单编号
        operateIntergralVo.setValue(orderInfo.getIntergral());//积分变动数值
        operateIntergralVo.setUserId(orderInfo.getUserId());//用户ID
        operateIntergralVo.setInfo(orderInfo.getProductName());//备注
        Result<String> result = integralFeignApi.decrIntergral(operateIntergralVo);
        if (result==null && result.hasError()){
            throw new BusinessException(SeckillCodeMsg.INTERGRAL_SERVER_ERROR);
        }
        //3.修改订单状态为已支付状态
        int count = orderInfoMapper.changePayStatus(orderNo, OrderInfo.STATUS_ACCOUNT_PAID, OrderInfo.PAYTYPE_INTERGRAL);
        if (count==0) {
            throw new BusinessException(SeckillCodeMsg.INTERGRAL_SERVER_ERROR);
        }
    }

    @Override
    @GlobalTransactional
    public void refundIntegral(OrderInfo orderInfo) {
        //1.插入流水记录
        RefundLog refundLog = new RefundLog();
        refundLog.setOutTradeNo(orderInfo.getOrderNo());//商品订单号
        refundLog.setRefundAmount(orderInfo.getIntergral() + "");//退款金额
        refundLog.setRefundTime(new Date());//退款时间
        refundLog.setRefundType(OrderInfo.PAYTYPE_INTERGRAL);//退款类型
        refundLog.setRefundReason("garbage 不要了");
        refundLogMapper.insert(refundLog);
        //2.远程调用积分服务进行退款操作
        OperateIntergralVo operateIntergralVo = new OperateIntergralVo();
        operateIntergralVo.setPk(orderInfo.getOrderNo());//订单编号
        operateIntergralVo.setValue(orderInfo.getIntergral());//积分变动数值
        operateIntergralVo.setUserId(orderInfo.getUserId());//用户ID
        operateIntergralVo.setInfo(orderInfo.getProductName());//备注
        Result<String> result = integralFeignApi.incrIntergral(operateIntergralVo);
        //3.修改订单状态为退款状态
        int count = orderInfoMapper.changeRefundStatus(orderInfo.getOrderNo(), OrderInfo.STATUS_REFUND);
        if (count==0) {
            throw new BusinessException(SeckillCodeMsg.OPT_ERROR);
        }
        int i = 1/0;
        //4.回补真实库存
        seckillProductMapper.incrStock(orderInfo.getSeckillId());
        //5.回补预库存
        seckillProductService.syncRedisStockCount(orderInfo.getSeckillTime(),orderInfo.getSeckillId());
        //6.修改本地标识
        rocketMQTemplate.sendOneWay(MQConstant.CANCEL_SECKILL_OVER_SIGE_TOPIC,orderInfo.getSeckillId());
    }
}
